#pragma once

#include <iostream>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"
#include <vector>
#include <queue>
#include <pthread.h>
#include <functional>

class ThreadData
{
public:
    ThreadData(const string &name)
        : threadname(name)
    {
    }
    ~ThreadData()
    {
    }

public:
    string threadname;
};

static const int defaultnum = 5;

template <class T>
class ThreadPool
{
public:
    // 线程池构造
    ThreadPool(int thread_num = defaultnum)
        : _thread_num(thread_num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        // 构建指定个数的线程
        for (int i = 0; i < _thread_num; i++)
        {
            string threadname = "thread-";
            threadname += to_string(i + 1);
            ThreadData td(threadname);
            // Thread<ThreadData> t(threadname, bind(&ThreadPool<T>::ThreadRun, this, placeholders::_1), td);
            // _threads.push_back(t);

            _threads.emplace_back(threadname, bind(&ThreadPool<T>::ThreadRun, this, placeholders::_1), td);
            lg.LogMessage(Info, "%s is created..\n", threadname.c_str());
        }
    }

    bool Start()
    {
        for (auto &thread : _threads)
        {
            thread.start();
            lg.LogMessage(Info, "%s is running..\n", thread.ThreadName().c_str());
        }
        return true;
    }

    void ThreadWait(const ThreadData &td)
    {
        lg.LogMessage(Debug, "no task, %s is sleeping...\n", td.threadname.c_str());
        pthread_cond_wait(&_cond, &_mutex);
    }

    void ThreadWakeup()
    {
        pthread_cond_signal(&_cond);
    }

    // 线程执行的方法
    void ThreadRun(ThreadData &td)
    {
        while (true)
        {
            // 取任务
            T t;
            {
                LockGuard lockguard(&_mutex);
                while (_q.empty())
                {
                    ThreadWait(td);
                }
                t = _q.front();
                _q.pop();
            }

            // 处理任务
            t();
            //打印日志消息
            lg.LogMessage(Info, "%s handler task %s done, result is:  %s\n", 
                td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
            sleep(1);
            cout << "handler done..." << t.PrintResult() << endl;

        }
    }

    void Push(T &in)
    {
        lg.LogMessage(Debug, "other thread push a task, task is : %s\n", in.PrintTask().c_str());
        LockGuard lockguard(&_mutex);
        _q.push(in);
        ThreadWakeup();
    }

    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    // for debug
    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
        }
    }

private:
    queue<T> _q;                         // 任务队列
    vector<Thread<ThreadData>> _threads; // 一批线程
    int _thread_num;                     // 线程个数
    pthread_mutex_t _mutex;              // 互斥锁
    pthread_cond_t _cond;                // 条件变量
};
